from datetime import datetime

from decimal import Decimal

from database import db_session

from flask import session

from models import *

from sqlalchemy import exc
from sqlalchemy import or_
from sqlalchemy import func

import os
import tipositem_mgr
import items_mgr
import pydot

############################Graficador##############################################
class Aristas():
    """
    Clase para representar las aristas de un grafo, se guardan los padres, los predecesores y los items involucrados
    """
    def __init__(self):
        """
        Constructor por defecto, inicializa todas las listas a vacio		
        """
        self.padres=[]
        self.predecesores=[]
        self.items=[]
    
def CalcularImpacto(listaItems):
    """
    Ejecuta el calculo de impacto sobre una lista de items, el calculo consiste en la suma de
    las complejidades de los items
    @param listaItems: lista de items involucrados
    @return: retorna el valor numerico del calculo de impacto
    """
    total = 0
    for item in listaItems:
        total = total + item.complejidad
    return total

def ConstruirGrafoIzquierdo (item, aristasIzquierda):
    """
    Contruye el subgrafo izquierdo
    @param item: item sobre el cual se debe construir el grafo
    @param aristasIzquierda: pasado por referencia, se agregaran todas las aristas del grafo
    """
    tipo_item = db_session.query(TipoItem).filter_by(id = item.fk_tipo_item).one()
    item_fase = tipo_item.fk_fase
    
    ancestros=db_session.query(Relacion).filter_by(fk_item_destino = item.id).all()
    if (item not in aristasIzquierda.items):
        aristasIzquierda.items.append(item)
        print '################################## 1'
        print item.nombre
        for relacion in ancestros:
            ancestro = db_session.query(Item).filter_by(id=relacion.fk_item_origen).first()
            print '################################## 1.1'
            print ancestro.nombre
            tipo_item_ancestro = db_session.query(TipoItem).filter_by( id = ancestro.fk_tipo_item).one()
            ancestro_fase = tipo_item_ancestro.fk_fase
            if (ancestro not in aristasIzquierda.predecesores):
                if (ancestro.estado != "ELI" and ancestro.estado != "INA" and ancestro_fase == item_fase ):
                    print '################################## Entro en grafo izq padre'
                    aristasIzquierda.padres.append(relacion)
                    ConstruirGrafoIzquierdo(ancestro, aristasIzquierda)
                elif (ancestro.estado != "ELI" and ancestro.estado != "INA"):
                    print '################################## Entro en grafo izq ancestro'
                    aristasIzquierda.predecesores.append(relacion)
                    ConstruirGrafoIzquierdo(ancestro, aristasIzquierda)

        #for relacion in item.relacionesPadres:
        #   if (relacion not in aristasIzquierda.padres):
        #       if (relacion.itemPadre.estado <> 7 and relacion.itemPadre.estado <> 6):
        #           aristasIzquierda.padres.append(relacion)
        #           ConstruirGrafoIzquierdo(relacion.itemPadre, aristasIzquierda)

def ConstruirGrafoDerecho (item, aristasDerecha):
    """
    Contruye el subgrafo derecho
    @param item: item sobre el cual se debe construir el grafo
    @param aristasDerecha: pasado por referencia, se agregaran todas las aristas del grafo
    """
    tipo_item = db_session.query(TipoItem).filter_by(id = item.fk_tipo_item).one()
    item_fase = tipo_item.fk_fase
    
    if(item not in aristasDerecha.items):
        aristasDerecha.items.append(item)
        print '################################## 2'
        print item.nombre
        sucesores = db_session.query(Relacion).filter_by(fk_item_origen=item.id).all()
        for relacion in sucesores:
            sucesor = db_session.query(Item).filter_by(id=relacion.fk_item_destino).first()
            tipo_item_sucesor = db_session.query(TipoItem).filter_by( id = sucesor.fk_tipo_item).one()
            sucesor_fase = tipo_item_sucesor.fk_fase
            print '################################## 2.1'
            print sucesor.nombre
            if (sucesor not in aristasDerecha.predecesores):				
                if (sucesor.estado != "ELI" and sucesor.estado != "INA" and sucesor_fase==item_fase):
                    print '################################## Entro en grafo der hijo'
                    aristasDerecha.padres.append(relacion)
                    ConstruirGrafoDerecho(sucesor, aristasDerecha)
                elif (sucesor.estado != "ELI" and sucesor.estado != "INA"):
                    print '################################## Entro en grafo der sucesor'
                    aristasDerecha.predecesores.append(relacion)
                    ConstruirGrafoDerecho(sucesor, aristasDerecha)

def CombinarYConstruir(item, aristasIzquierda, aristasDerecha, aristasTotales):
    """
    Combina las aristas de los subgrafos izquierdo y derecho para generar el grafo completo,
    despues de combinar construye los 3 grafos y los guarda como archivos png en el directorio 
    /public/images del proyecto
    @param item: entidad del item actual
    @param aristasIzquierda: aristas del subgrafo izquierdo
    @param aristasDerecha: aristas del subgrafo derecho
    @param aristasTotales: aristas del grafo completo
    """
    graficoIzq = pydot.Dot(graph_type='digraph')
    graficoDer = pydot.Dot(graph_type='digraph')
    graficoTotal = pydot.Dot(graph_type='digraph')
    
    nodoInicial = pydot.Node(item.nombre + " " + items_mgr.obtener_nombre_fase_item(item.id), style="filled", fillcolor="yellow")
    
    graficoIzq.add_node(nodoInicial)
    graficoDer.add_node(nodoInicial)
    graficoTotal.add_node(nodoInicial)
    
    #-----------------------------#
    #  Combinando lista de items  #
    #-----------------------------#
    for item in aristasIzquierda.items:
        aristasTotales.items.append(item)
    for item in aristasDerecha.items:
        if (item not in aristasTotales.items):
            aristasTotales.items.append(item)

    #-----------------------------------------------------------------------------#
    #Construyendo Grafo Izquierdo y agregando las relaciones nuevas al grafo total#
    #-----------------------------------------------------------------------------#
    for relacion in aristasIzquierda.predecesores:
        itemOrigen = db_session.query(Item).filter_by(id=relacion.fk_item_origen).first()
        itemDestino = db_session.query(Item).filter_by(id=relacion.fk_item_destino).first()
        enlace = pydot.Edge(itemOrigen.nombre + " " + items_mgr.obtener_nombre_fase_item(itemOrigen.id), itemDestino.nombre + " " + items_mgr.obtener_nombre_fase_item(itemDestino.id))
        graficoIzq.add_edge(enlace)
        if (relacion not in aristasTotales.predecesores):
            aristasTotales.predecesores.append(relacion)

    for relacion in aristasIzquierda.padres:
        itemOrigen = db_session.query(Item).filter_by(id=relacion.fk_item_origen).first()
        itemDestino = db_session.query(Item).filter_by(id=relacion.fk_item_destino).first()
        enlace = pydot.Edge(itemOrigen.nombre + " " + items_mgr.obtener_nombre_fase_item(itemOrigen.id), itemDestino.nombre + " " + items_mgr.obtener_nombre_fase_item(itemDestino.id))
        graficoIzq.add_edge(enlace)
        if (relacion not in aristasTotales.padres):
            aristasTotales.padres.append(relacion)

    #---------------------------------------------------------------------------#
    #Construyendo Grafo Derecho y agregando las relaciones nuevas al grafo total#
    #---------------------------------------------------------------------------#
    for relacion in aristasDerecha.predecesores:
        itemOrigen=db_session.query(Item).filter_by(id=relacion.fk_item_origen).first()
        itemDestino = db_session.query(Item).filter_by(id=relacion.fk_item_destino).first()
        enlace = pydot.Edge(itemOrigen.nombre + " " + items_mgr.obtener_nombre_fase_item(itemOrigen.id), itemDestino.nombre + " " + items_mgr.obtener_nombre_fase_item(itemDestino.id))
        graficoDer.add_edge(enlace)
        if (relacion not in aristasTotales.predecesores):
            aristasTotales.predecesores.append(relacion)

    for relacion in aristasDerecha.padres:
        itemOrigen=db_session.query(Item).filter_by(id=relacion.fk_item_origen).first()
        itemDestino = db_session.query(Item).filter_by(id=relacion.fk_item_destino).first()
        enlace = pydot.Edge(itemOrigen.nombre + " " + items_mgr.obtener_nombre_fase_item(itemOrigen.id), itemDestino.nombre + " " + items_mgr.obtener_nombre_fase_item(itemDestino.id))
        graficoDer.add_edge(enlace)
        if (relacion not in aristasTotales.padres):
            aristasTotales.padres.append(relacion)

    #----------------------------------#
    #  Construyendo el Grafo Completo  #
    #----------------------------------#
    for relacion in aristasTotales.predecesores:
        itemOrigen=db_session.query(Item).filter_by(id=relacion.fk_item_origen).first()
        itemDestino = db_session.query(Item).filter_by(id=relacion.fk_item_destino).first()
        enlace = pydot.Edge(itemOrigen.nombre + " " + items_mgr.obtener_nombre_fase_item(itemOrigen.id), itemDestino.nombre + " " + items_mgr.obtener_nombre_fase_item(itemDestino.id))
        graficoTotal.add_edge(enlace)

    for relacion in aristasTotales.padres:
        itemOrigen=db_session.query(Item).filter_by(id=relacion.fk_item_origen).first()
        itemDestino = db_session.query(Item).filter_by(id=relacion.fk_item_destino).first()
        enlace = pydot.Edge(itemOrigen.nombre + " " + items_mgr.obtener_nombre_fase_item(itemOrigen.id), itemDestino.nombre + " " + items_mgr.obtener_nombre_fase_item(itemDestino.id))
        graficoTotal.add_edge(enlace)

    #log.debug(os.path.join(os.path.dirname(scp.__file__), "public/images/grafoIzq.png"))
    graficoIzq.write_png(os.path.join(os.path.dirname("./"), "grafo/grafoIzq.png"))
    graficoDer.write_png(os.path.join(os.path.dirname("./"), "grafo/grafoDer.png"))
    graficoTotal.write_png(os.path.join(os.path.dirname("./"), "grafo/grafoTotal.png"))
    
    return None

def GenerarGrafoCompleto(item, aristas):
    """
    Construye el grafo completo de un item
    @param item: entidad del item sobre el cual se esta construyendo
    @param aristas: pasado por referencia, se agregan todas las aristas del grafo
    @return: xxx
    """
    #si este item ya fue evaluado, retorno
    if (item in aristas.items):
        print("El item ya existe....  ", str(item.id), " Retornando...")
        return

    print("Agregando item "+ str(item.id) + " a la lista de involucrados")
    aristas.items.append(item)
    
    #primero evaluo los predecesores del item actual
    for relacion in item.relacionPredecesores:

        #si mi predecesor se encuentra bloqueado es un candidato
        if (relacion.itemPredecesor.estado == "BLO"):
            #si esta relacion no se encuentra en la lista de aristas, entonces lo agrego
            if (relacion not in aristas.predecesores):

                if (relacion.itemPredecesor.estado != "INA" and relacion.itemPredecesor.estado != "ELI"):

                    if (relacion.itemPredecesor.estado == "BLO" or relacion.itemPredecesor.estado == "COM"):

                        print("Agregando relacion- Predecesor:", relacion.itemPredecesor.id, "Sucesor;", relacion.itemSucesor.id)
                        aristas.predecesores.append(relacion)
                        GenerarGrafoCompleto(relacion.itemPredecesor, aristas)

    #2do evaluo los sucesores del item actual
    for relacion in item.relacionSucesores:
        #si mi sucesor se encuentra bloqueado es un candidato
        if (relacion.itemSucesor.estado == "BLO"):
            #si esta relacion no se encuentra en la lista de aristas, entonces lo agrego
            if (relacion not in aristas.predecesores):
    
                if (relacion.itemSucesor.estado <> "INA" and relacion.itemSucesor.estado <> "ELI"):

                    if (relacion.itemSucesor.estado == "BLO" or relacion.itemSucesor.estado == "COM"):

                        print("Agregando relacion- Predecesor:", relacion.itemPredecesor.id, "Sucesor;", relacion.itemSucesor.id)
                        aristas.predecesores.append(relacion)
                        GenerarGrafoCompleto(relacion.itemSucesor, aristas)

    #3ro con los predecesores, evaluo los padres
    for relacion in item.relacionesPadres:
        #si mi padre se encuentra bloqueado es un candidato
        if (relacion.itemPadre.estado == "BLO"):
            #si esta relacion no esta en la lista de aristas, lo agrego
            if(relacion not in aristas.padres):

                if (relacion.itemPadre.estado != "INA" and relacion.itemPadre.estado != "ELI"):

                    if (relacion.itemPadre.estado == "BLO" or relacion.itemPadre.estado == "COM"):

                        print("Agregando relacion- Padre:", relacion.itemPadre.id, "Hijo;", relacion.itemHijo.id)
                        aristas.padres.append(relacion)
                        GenerarGrafoCompleto(relacion.itemPadre, aristas)	

    #terminado con los predecesores, evaluo los hijos
    for relacion in item.relacionesHijos:
        #si mi padre se encuentra bloqueado es un candidato
        if (relacion.itemHijo.estado == "BLO"):
            #si esta relacion no esta en la lista de aristas, lo agrego
            if(relacion not in aristas.padres):

                if (relacion.itemHijo.estado != "INA" and relacion.itemHijo.estado != "ELI"):

                    if (relacion.itemHijo.estado == "BlO" or relacion.itemHijo.estado == "COM"):

                        print("Agregando relacion- Padre:", relacion.itemPadre.id, "Hijo;", relacion.itemHijo.id)
                        aristas.padres.append(relacion)
                        GenerarGrafoCompleto(relacion.itemHijo, aristas)
                        
    print("Fin de la exploracion, retornando")
    return None

############################Fin Graficador##########################################
